using System;
using System.Collections.Generic;
using System.Text;
using Spring.Data.NHibernate.Generic;
using NHibernate;
using NHibernate.Criterion;

namespace Gestion.Lib.Data
{
    public delegate IList<T> MyFindHibernateDelegate<T>(ISession session);

    public class MyExecuteFindHibernateCallbackUsingDelegate<T> : IFindHibernateCallback<T>
    {
        private MyFindHibernateDelegate<T> del;

        public MyExecuteFindHibernateCallbackUsingDelegate(MyFindHibernateDelegate<T> del)
        {
            this.del = del;
        }

        IList<T> IFindHibernateCallback<T>.DoInHibernate(NHibernate.ISession session)
        {
            return del(session);
        }
    }

    public abstract class HibernateReadOnlyDao<T, ID> : Spring.Data.NHibernate.Generic.Support.HibernateDaoSupport//Spring.Data.NHibernate.Generic.Support.HibernateDaoSupport
    {
        private string entityName = typeof(T).Name;
        /// <summary>
        /// Execute to find using a delegate
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="del"></param>
        /// <returns></returns>
        protected IList<T> ExecuteFind<T>(MyFindHibernateDelegate<T> del)
        {
            return HibernateTemplate.ExecuteFind<T>(new MyExecuteFindHibernateCallbackUsingDelegate<T>(del), true);
        }

        /// <summary>
        /// Gets by ID
        /// </summary>
        /// <param name="id"></param>
        public T GetById(ID id)
        {
            T entity = HibernateTemplate.Get<T>(id, NHibernate.LockMode.None);
            return entity;
        }

        /// <summary>
        /// Counts all entities
        /// </summary>
        /// <returns></returns>
        public int CountAll()
        {
            return HibernateTemplate.Execute<int>(
                delegate(ISession session)
                {
                    return session.CreateQuery("select count(e.Id) from " + entityName + " e").UniqueResult<int>();
                }
            );
        }

        /// <summary>
        /// Finds all entities
        /// </summary>
        /// <returns></returns>
        public IList<T> FindAll()
        {
            return HibernateTemplate.Find<T>("from " + entityName + " e");
        }

        /// <summary>
        /// Finds all with a given order
        /// </summary>
        /// <param name="order"></param>
        /// <param name="desc"></param>
        /// <returns></returns>
        public IList<T> FindAll(string order, bool desc)
        {
            return ExecuteFind<T>(
                delegate(ISession session)
                {
                    if (desc)
                    {
                        return session.CreateCriteria(typeof(T)).AddOrder(Order.Desc(order)).List<T>();
                    }
                    else
                    {                        
                        return session.CreateCriteria(typeof(T)).AddOrder(Order.Asc(order)).List<T>();
                    }
                }
                );
        }
        /// <summary>
        ///  Finds all entities, in a paged way
        /// </summary>
        /// <param name="firstRow"></param>
        /// <param name="maxRows"></param>
        /// <returns></returns>
        public IList<T> FindAll(int firstRow, int maxRows)
        {
            return ExecuteFind<T>(
                delegate(ISession session)
                {
                    return session.CreateQuery("from " + entityName + " e").SetFirstResult(firstRow).SetMaxResults(maxRows).List<T>();
                }
                );
        }

        /// <summary>
        /// FInds by text
        /// </summary>
        /// <param name="value"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public IList<T> FindByText(String value, String[] args)
        {
            return ExecuteFind<T>(
                delegate(ISession session)
                {
                    ICriteria criteria = session.CreateCriteria(typeof(T));
                    ICriterion OldExp;
                    ICriterion NewExp;

                    OldExp = NewExp = null;
                    for (int i = 0; i < args.Length; i++)
                    {
                        if (OldExp == null)
                        {
                            NewExp = Expression.Like(args[i], value);
                        }
                        else
                        {
                            NewExp = Expression.Or(Expression.Like(args[i], value), OldExp);
                            
                        }
                        OldExp = NewExp;
                        criteria.AddOrder(Order.Asc(args[i]));
                        
                    }
                    criteria.Add(OldExp);
                    criteria.SetMaxResults(150);
                    return criteria.List<T>();
                }
                );
        }
 
        /// <summary>
        /// Finds by text with a defined filter
        /// </summary>
        /// <param name="text"></param>
        /// <param name="columns"></param>
        /// <param name="filterColumn"></param>
        /// <param name="filterValue"></param>
        /// <returns></returns>
        public IList<T> FindByTextFiltered(String text, String[] columns, String filterColumn, object filterValue)
        {
            return ExecuteFind<T>(
                delegate(ISession session)
                {
                    ICriteria criteria = session.CreateCriteria(typeof(T));
                    ICriterion exp;

                    exp = null;
                    for (int i = 0; i < columns.Length; i++)
                    {
                        if (exp == null)
                        {
                            exp = Expression.Like(columns[i], text);
                        }
                        else
                        {
                            exp = Expression.Or(Expression.Like(columns[i], text), exp);
                        }
                    }
                    exp = Expression.And(Expression.Eq(filterColumn, filterValue), exp);

                    criteria.Add(exp);
                    criteria.SetMaxResults(50);
                    return criteria.List<T>();
                }
                );
        }
    }
}
